// 布隆过滤器管理器

import { BaseManager } from '../core/BaseManager';
import { RedisClient } from '../core/RedisClient';
import { KeyGenerator } from '../utils/keyGenerator';

export interface BloomFilterOptions {
  capacity?: number; // 预期元素数量
  errorRate?: number; // 误判率
  hashFunctions?: number; // 哈希函数数量
  bitSize?: number; // 位数组大小
}

export interface BloomFilterInfo {
  capacity: number;
  errorRate: number;
  hashFunctions: number;
  bitSize: number;
  insertedCount: number;
  estimatedFalsePositiveRate: number;
}

export interface BloomFilterStats {
  totalFilters: number;
  totalElements: number;
  averageCapacity: number;
  memoryUsage: number;
}

export class BloomFilterManager extends BaseManager {
  private defaultOptions: Required<BloomFilterOptions> = {
    capacity: 10000,
    errorRate: 0.01,
    hashFunctions: 7,
    bitSize: 95851, // 计算得出的最优位数组大小
  };

  constructor(client: RedisClient) {
    super(client, new KeyGenerator({ prefix: 'bloom' }));
  }

  /**
   * 创建布隆过滤器
   */
  async create(name: string, options: BloomFilterOptions = {}): Promise<BloomFilterInfo> {
    this.validateRequired({ name });

    const config = { ...this.defaultOptions, ...options };

    // 如果提供了容量和误判率，重新计算最优参数
    if (options.capacity ?? options.errorRate) {
      const optimized = this.calculateOptimalParameters(config.capacity, config.errorRate);
      config.bitSize = optimized.bitSize;
      config.hashFunctions = optimized.hashFunctions;
    }

    const filterKey = this.keyGenerator.generate('filter', name);
    const infoKey = this.keyGenerator.generate('info', name);

    const startTime = this.now();

    try {
      // 检查是否已存在
      const exists = (await this.getValue(filterKey)) !== null;
      if (exists) {
        throw new Error(`Bloom filter '${name}' already exists`);
      }

      // 初始化位数组（使用字符串存储）
      await this.setValue(filterKey, '0'.repeat(Math.ceil(config.bitSize / 8)));

      // 存储过滤器信息
      const info: BloomFilterInfo = {
        capacity: config.capacity,
        errorRate: config.errorRate,
        hashFunctions: config.hashFunctions,
        bitSize: config.bitSize,
        insertedCount: 0,
        estimatedFalsePositiveRate: 0,
      };

      await this.setValue(infoKey, JSON.stringify(info));

      this.logMetric('bloom.create', this.now() - startTime, true, {
        name,
        capacity: config.capacity,
        errorRate: config.errorRate,
        bitSize: config.bitSize,
      });

      return info;
    } catch (error) {
      this.logMetric('bloom.create', this.now() - startTime, false, {
        name,
        error: (error as Error).message,
      });
      throw this.formatError(error, `Failed to create bloom filter: ${name}`);
    }
  }

  /**
   * 添加元素到布隆过滤器
   */
  async add(name: string, element: string): Promise<boolean> {
    this.validateRequired({ name, element });

    const filterKey = this.keyGenerator.generate('filter', name);
    const infoKey = this.keyGenerator.generate('info', name);

    const startTime = this.now();

    try {
      // 获取过滤器信息
      const info = await this.getFilterInfo(name);
      if (!info) {
        throw new Error(`Bloom filter '${name}' does not exist`);
      }

      // 计算哈希值
      const hashes = this.calculateHashes(element, info.hashFunctions, info.bitSize);

      // 检查是否可能已存在
      const mightExist = await this.mightContain(name, element);

      // 设置对应的位
      const pipeline = this.createPipeline();
      for (const hash of hashes) {
        pipeline.setbit(filterKey, hash, 1);
      }
      await pipeline.exec();

      // 如果元素可能不存在，更新计数
      if (!mightExist) {
        info.insertedCount++;
        info.estimatedFalsePositiveRate = this.calculateFalsePositiveRate(
          info.insertedCount,
          info.bitSize,
          info.hashFunctions
        );
        await this.setValue(infoKey, JSON.stringify(info));
      }

      this.logMetric('bloom.add', this.now() - startTime, true, {
        name,
        element: element.substring(0, 50), // 限制日志长度
        wasNew: !mightExist,
      });

      return !mightExist;
    } catch (error) {
      this.logMetric('bloom.add', this.now() - startTime, false, {
        name,
        error: (error as Error).message,
      });
      throw this.formatError(error, `Failed to add element to bloom filter: ${name}`);
    }
  }

  /**
   * 检查元素是否可能存在
   */
  async mightContain(name: string, element: string): Promise<boolean> {
    this.validateRequired({ name, element });

    const filterKey = this.keyGenerator.generate('filter', name);

    const startTime = this.now();

    try {
      // 获取过滤器信息
      const info = await this.getFilterInfo(name);
      if (!info) {
        throw new Error(`Bloom filter '${name}' does not exist`);
      }

      // 计算哈希值
      const hashes = this.calculateHashes(element, info.hashFunctions, info.bitSize);

      // 检查所有对应的位
      const pipeline = this.createPipeline();
      for (const hash of hashes) {
        pipeline.getbit(filterKey, hash);
      }

      const results = await pipeline.exec();
      const allBitsSet = results.every((result: any) => result[1] === 1);

      this.logMetric('bloom.check', this.now() - startTime, true, {
        name,
        element: element.substring(0, 50),
        result: allBitsSet,
      });

      return allBitsSet;
    } catch (error) {
      this.logMetric('bloom.check', this.now() - startTime, false, {
        name,
        error: (error as Error).message,
      });
      throw this.formatError(error, `Failed to check element in bloom filter: ${name}`);
    }
  }

  /**
   * 批量添加元素
   */
  async addMultiple(name: string, elements: string[]): Promise<number> {
    this.validateRequired({ name, elements });

    let addedCount = 0;
    for (const element of elements) {
      const wasNew = await this.add(name, element);
      if (wasNew) {
        addedCount++;
      }
    }

    return addedCount;
  }

  /**
   * 批量检查元素
   */
  async mightContainMultiple(name: string, elements: string[]): Promise<boolean[]> {
    this.validateRequired({ name, elements });

    const results: boolean[] = [];
    for (const element of elements) {
      const exists = await this.mightContain(name, element);
      results.push(exists);
    }

    return results;
  }

  /**
   * 获取布隆过滤器信息
   */
  async getInfo(name: string): Promise<BloomFilterInfo | null> {
    this.validateRequired({ name });

    return this.getFilterInfo(name);
  }

  /**
   * 删除布隆过滤器
   */
  async delete(name: string): Promise<boolean> {
    this.validateRequired({ name });

    const filterKey = this.keyGenerator.generate('filter', name);
    const infoKey = this.keyGenerator.generate('info', name);

    try {
      const deletedCount = await this.deleteKeys(filterKey, infoKey);
      return deletedCount > 0;
    } catch (error) {
      throw this.formatError(error, `Failed to delete bloom filter: ${name}`);
    }
  }

  /**
   * 获取统计信息
   */
  async getStats(): Promise<BloomFilterStats> {
    try {
      const pattern = this.keyGenerator.generate('info', '*');
      const infoKeys = await this.getKeys(pattern);

      let totalElements = 0;
      let totalCapacity = 0;
      let totalMemory = 0;

      for (const key of infoKeys) {
        const infoStr = await this.getValue<string>(key);
        if (infoStr) {
          const info: BloomFilterInfo = JSON.parse(infoStr);
          totalElements += info.insertedCount;
          totalCapacity += info.capacity;
          totalMemory += Math.ceil(info.bitSize / 8);
        }
      }

      return {
        totalFilters: infoKeys.length,
        totalElements,
        averageCapacity: infoKeys.length > 0 ? totalCapacity / infoKeys.length : 0,
        memoryUsage: totalMemory,
      };
    } catch (error) {
      throw this.formatError(error, 'Failed to get bloom filter stats');
    }
  }

  /**
   * 获取过滤器信息
   */
  private async getFilterInfo(name: string): Promise<BloomFilterInfo | null> {
    const infoKey = this.keyGenerator.generate('info', name);
    const infoStr = await this.getValue<string>(infoKey);

    if (!infoStr) {
      return null;
    }

    return JSON.parse(infoStr);
  }

  /**
   * 计算最优参数
   */
  private calculateOptimalParameters(
    capacity: number,
    errorRate: number
  ): {
    bitSize: number;
    hashFunctions: number;
  } {
    // 计算最优位数组大小: m = -n * ln(p) / (ln(2)^2)
    const bitSize = Math.ceil((-capacity * Math.log(errorRate)) / Math.log(2) ** 2);

    // 计算最优哈希函数数量: k = (m/n) * ln(2)
    const hashFunctions = Math.ceil((bitSize / capacity) * Math.log(2));

    return { bitSize, hashFunctions };
  }

  /**
   * 计算哈希值
   */
  private calculateHashes(element: string, hashFunctions: number, bitSize: number): number[] {
    const hashes: number[] = [];

    // 使用简单的哈希函数组合
    const hash1 = this.simpleHash(element);
    const hash2 = this.simpleHash(element + 'salt');

    for (let i = 0; i < hashFunctions; i++) {
      const hash = (hash1 + i * hash2) % bitSize;
      hashes.push(Math.abs(hash));
    }

    return hashes;
  }

  /**
   * 简单哈希函数
   */
  private simpleHash(str: string): number {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = (hash << 5) - hash + char;
      hash = hash & hash; // 转换为32位整数
    }
    return hash;
  }

  /**
   * 计算误判率
   */
  private calculateFalsePositiveRate(
    insertedCount: number,
    bitSize: number,
    hashFunctions: number
  ): number {
    // 计算实际误判率: (1 - e^(-k*n/m))^k
    const ratio = (hashFunctions * insertedCount) / bitSize;
    return Math.pow(1 - Math.exp(-ratio), hashFunctions);
  }
}
